<template>
  <!-- 表单容器，使用flex布局 -->
  <div class="flex justify-start">
    <!-- Element Plus表单组件 -->
    <el-form
      ref="ruleFormRef"
      class="form-container overflow-hidden w-full"
      novalidate
      :inline="isInline"
      :model="formInline"
      :label-width="labelWidth"
      :label-position="labelPosition as any"
    >
      <!-- 表单行容器 -->
      <el-row
        :class="['gap-y-[18px] au-form-row', isInline ? '' : 'pb-[18px]']"
        :gutter="10"
      >
        <!-- 遍历表单项 -->
        <template v-for="item in subColumns" :key="item.key">
          <!-- 表单列，根据是否内联决定宽度 -->
          <el-col v-if="!item.hidden" :span="isInline ? item.span ?? 6 : 24">
            <!-- 表单项组件 -->
            <el-form-item
              :label="te(item.label) ? t(item.label) : item.label"
              :prop="item.key"
              :required="Boolean(item.required)"
              :rules="item.rules"
              :label-width="item.labelWidth"
            >
              <!-- 表单项后置插槽 -->
              <slot :name="`${item.key}_before`" />
              <!-- 动态渲染表单控件组件 -->
              <component
                :is="item.component"
                v-if="!item.slot"
                v-model="formInline[item.key]"
                v-bind="propOmit(item)"
                :label="te(item.compLabel) ? t(item.compLabel) : item.compLabel"
                :placeholder="
                  te(item.placeholder) ? t(item.placeholder) : item.placeholder
                "
                :startPlaceholder="
                  te(item.startPlaceholder)
                    ? t(item.startPlaceholder)
                    : item.startPlaceholder
                "
                :endPlaceholder="
                  te(item.endPlaceholder)
                    ? t(item.endPlaceholder)
                    : item.endPlaceholder
                "
                @change="
                  e => (item.onChange ? item.onChange(e) : compChange(e, item))
                "
              />

              <!-- 渲染表单项后置组件 -->
              <component :is="item.behindRender" v-if="item.behindRender" />
              <!-- 表单项后置插槽 -->
              <slot :name="`${item.key}_behind`" />

              <!-- 自定义标签插槽 -->
              <template #label>
                <slot :name="`${item.key}_label`" :label="item.label" />
              </template>
            </el-form-item>
          </el-col>
        </template>
        <!-- 表单按钮区域 -->
        <el-form-item v-if="!hiddenBtn" :class="['btn_']">
          <!-- 搜索按钮 -->
          <el-button v-if="!isAutoSearch" type="primary" @click="submit">
            {{ t("buttons.search") }}
          </el-button>
          <!-- 重置按钮 -->
          <el-button
            :type="isAutoSearch ? 'primary' : ''"
            :link="isAutoSearch"
            @click="reset"
          >
            {{ t("buttons.reset") }}
          </el-button>
          <!-- 导出按钮 -->
          <el-button
            v-if="props.exportBtnFlag"
            type="success"
            @click="exportPdf"
          >
            {{ t("table.export") }}
          </el-button>
          <!-- 展开/收起按钮 -->
          <el-button
            v-if="hasUnfold && formListProcess.length > showNumber"
            class="ml-2"
            type="primary"
            link
            @click="handleUnfold"
          >
            {{ isShowUnfold ? $t("search.retract") : $t("search.expand") }}
            <span class="text-icon-12">
              <FontIcon :icon="isShowUnfold ? 'icon-up' : 'icon-down'" />
            </span>
          </el-button>
        </el-form-item>
        <!-- 表单后置插槽 -->
        <slot name="form_behind" />
      </el-row>
    </el-form>
  </div>
</template>

<script setup lang="ts">
// 导入Vue核心功能
import { ref, watch, shallowRef, computed, useSlots, toRef } from "vue";
// 导入工具函数
import { defProps, handleDefValue, handleFormList, propOmit } from "./tools";
// 导入Element Plus组件
import { ElMessage } from "element-plus";
// 导入lodash工具函数
import { cloneDeep, assign } from "lodash-unified";
// 导入类型定义
import { BaseProps, inputProps, selectProps } from "@/components/AuForm/type";
// 导入工具函数
import { isArray, isString } from "@pureadmin/utils";
import { useI18n } from "vue-i18n";

// 定义组件属性
const props = defineProps(defProps);
const { t, te, locale } = useI18n();

// 表单数据对象
const formInline = ref({});
// 处理后的表单项列表
const formListProcess = shallowRef([]);
// 通过setFormProps处理后的数据
const assignFormList = ref([]);

// 是否展开更多表单项
const isShowUnfold = ref(false);

// 表单引用，用于表单验证
const ruleFormRef = ref();

// 定义组件事件
const emit = defineEmits([
  "submit", // 提交事件
  "reset", // 重置事件
  "collapse", // 折叠事件
  "change", // 值变化事件
  "exportPdf" // 导出PDF事件
]);

// 计算显示的表单项
const subColumns = computed(() => {
  if (props.hasUnfold && !isShowUnfold.value) {
    // 如果有折叠功能且未展开，只显示指定数量的表单项
    return formListProcess.value.slice(0, props.showNumber);
  } else {
    // 否则显示全部表单项
    return formListProcess.value;
  }
});

/**
 * 处理表单值，将特殊值"/"转换为空字符串
 * @param val 原始表单数据
 * @returns 处理后的表单数据
 */
const handleVal = (val: Record<string, any>) => {
  const res = {};
  for (const key in val) {
    res[key] = val[key] === "/" ? "" : val[key];
  }
  return res;
};

// 初始化表单数据
formInline.value = assign(
  handleDefValue(props.formList), // 获取默认值
  handleVal(props.formData) // 合并传入的表单数据
);

// 定义选项类型
type optionType =
  | inputProps
  | selectProps
  | { [key: string]: inputProps | selectProps };

/**
 * 设置表单项属性
 * @param key 表单项键名或键名数组
 * @param option 要设置的属性
 */
const setFormProps = async (key: string | string[], option: optionType) => {
  const _formList = cloneDeep(assignFormList.value);
  if (isArray(key)) {
    // 如果是数组，批量设置多个表单项
    for (const item of _formList) {
      const find = key.find(v => item.key === v);
      if (find) {
        assign(item, option[find]);
      }
    }
  } else {
    // 设置单个表单项
    for (const item of _formList) {
      if (item.key === key) {
        assign(item, option);
      }
    }
  }
  console.log(_formList);
  // 更新表单项列表
  assignFormList.value = cloneDeep(_formList);
  formListProcess.value = await handleFormList(_formList, props, {
    te,
    t,
    locale
  });
};

/**
 * 表单控件值变化处理函数
 * @param val 新值
 * @param item 表单项配置
 */
const compChange = (val: any, item: BaseProps) => {
  // formInline.value[item.key] = val;
  emit("change", { key: item.key, value: val });
};

/**
 * 提交表单
 */
const submit = async () => {
  await ruleFormRef.value.validate((valid, fields) => {
    if (valid) {
      // 验证通过，触发submit事件
      const formData = {};
      for (const key in formInline.value) {
        formData[key] = isString(formInline.value[key])
          ? formInline.value[key].trim()
          : formInline.value[key];
      }
      emit("submit", formData);
    } else {
      // 验证失败，输出错误信息
      console.log("error submit!", fields);
      // 以下是被注释的错误提示代码
      // const firstKey = Object.keys(fields)[0];
      // ElMessage({
      //   message: `${firstKey}必须填写！`,
      //   type: "error"
      // });
    }
  });
};

/**
 * 表单验证方法
 * @returns Promise，包含验证结果
 */
const validate = () => {
  return new Promise(resolve => {
    ruleFormRef.value.validate((valid, fields) => {
      if (valid) {
        resolve({
          check: true
        });
      } else {
        resolve({
          check: false
        });
      }
    });
  });
};

/**
 * 重置表单
 */
const reset = () => {
  // 重置表单字段
  ruleFormRef.value.resetFields();
  // 恢复默认值
  const defVal = {};
  for (const item of props.formList) {
    if (item.defaultValue) {
      defVal[item.key] = item.defaultValue;
    }
  }
  formInline.value = defVal;
  // 如果按钮未隐藏，自动提交
  !props.hiddenBtn && submit();
  // 触发重置事件
  emit("reset");
};

/**
 * 设置表单数据
 * @param val 要设置的数据
 */
const setFormData = (val: Record<string, any>) => {
  formInline.value = assign(formInline.value, handleVal(val));
};

/**
 * 处理展开/收起操作
 * @param e 鼠标事件
 */
const handleUnfold = (e: MouseEvent) => {
  e.preventDefault();
  isShowUnfold.value = !isShowUnfold.value;
  emit("collapse", isShowUnfold.value);
};

/**
 * 导出PDF
 */
const exportPdf = () => {
  // console.log("导出");
  emit("exportPdf");
};

// 监听表单列表变化
watch(
  [() => props.formList],
  async () => {
    assignFormList.value = cloneDeep(props.formList);
    formListProcess.value = await handleFormList(props.formList, props, {
      te,
      t,
      locale
    });
  },
  {
    immediate: true // 立即执行一次
  }
);

watch(
  () => locale.value,
  async () => {
    formListProcess.value = await handleFormList(assignFormList.value, props, {
      te,
      t,
      locale
    });
  }
);

// 监听表单数据变化
watch(() => props.formData, setFormData, {
  deep: true // 深度监听
});

// 暴露组件方法
defineExpose({
  getFormData() {
    const formData = {};
    for (const key in formInline.value) {
      formData[key] = isString(formInline.value[key])
        ? formInline.value[key].trim()
        : formInline.value[key];
    }
    return formData;
  },
  setFormProps,
  setFormData,
  submit,
  reset,
  validate
});
</script>

<style scoped lang="scss">
/* 表单项样式 */
:deep(.el-form-item) {
  width: 100%;
  margin-right: 0;
  margin-bottom: 0;
}

/* 按钮区域样式 */
.btn_ {
  display: flex;
  flex: auto;
  align-items: flex-start;
  justify-content: flex-end;
  width: auto !important;
  max-width: 100%;
  margin-right: 5px;
  margin-bottom: 0;

  :deep(.el-form-item__content) {
    flex: none;
    flex-wrap: nowrap;
  }
}

/* 按钮靠右对齐样式 */
.btn_end {
  :deep(.el-form-item__content) {
    justify-content: end;
  }
}

/* 图标文本样式 */
.text-icon-12 {
  .iconfont {
    margin-left: 2px;
    font-size: 12px;
  }
}
</style>
